package com.nowcoder.community.controller;

import com.google.code.kaptcha.Producer;
import com.nowcoder.community.entity.User;
import com.nowcoder.community.service.UserService;
import com.nowcoder.community.util.CommunityConstant;
import com.nowcoder.community.util.GenerateUtil;
import com.nowcoder.community.util.RedisKeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.imageio.ImageIO;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @BelongsProject: community
 * @BelongsPackage: com.nowcoder.community.controller
 * @Author: Master_XXJS
 * @CreateTime: 2022-09-17  23:46
 * @Description: TODO 注册功能
 * @Version: 1.0
 */
@Slf4j
@Controller
public class LoginController implements CommunityConstant {

    @Autowired
    private UserService userService;
    @Autowired
    private Producer kaptchaProducer;
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("server.servlet.context-path")
    private String contextPath;


    /**
     * @description: 页面导航栏，点击注册的时候，跳转到这里，通过 controller 实现页面的跳转
     * @author: Master_XXJS
     * @date: 2022/9/19 10:18
     * @param: []
     * @return: java.lang.String
     **/
    @RequestMapping(value = "/register",method = RequestMethod.GET)
    public String registerPage(){
        return "/site/register.html";
    }

    /**
     *  跳转登录成功的页面
     * @return
     */
    @RequestMapping(value = "/login",method = RequestMethod.GET)
    public String loginPage(){
        return "/site/login.html";
    }



    /**
     * @description: 注册功能
     * @author: Master_XXJS
     * @date: 2022/9/18 22:30
     * @param: [model, user 前端提交的 user 信息的表格]
     * @return: java.lang.String
     **/
    @RequestMapping(value = "/register",method = RequestMethod.POST)
    public String register(Model model, User user){
        //输出日志调试
        log.info("注册用户");

        // 创建一个 map 集合
        Map<String, Object> map = userService.register(user);

        // 对 map 进行判断
        if (map == null || map.isEmpty()){
            //如果 msg 为null，因为 msg 是错误的信息提示，所以注册成功
            model.addAttribute("msg","注册成功，我们已经向您的邮箱发送了一份邮件，请尽快激活！");
            model.addAttribute("target","/index"); // 激活之后我们进行跳转的路径，也可以跳转到登录页面，注意注册成功不是登录成功

            // TODO: 2022/9/19 这里应该加一个进行对激活的验证
            /*
                等待用户点击激活邮件，可以在 进行用户激活方法（下面那一个）加一个redis缓存
                我们可以通过 redis 缓存进行读取是否存在，如果存在了，就说明用户已经点击 激活成功
                那么我们就跳转激活成功的页面，提示用户
             */

            return "/site/operate-result.html";  // 跳到提示我们需要进行激活的页面
        } else {
            model.addAttribute("usernameMsg",map.get("usernameMsg"));
            model.addAttribute("passwordMag",map.get("passwordMag"));
            model.addAttribute("emailMsg",map.get("emailMsg"));
            return "/site/register.html"; //注册失败，重新跳到注册页面进行注册
        }
    }

    /**
     * 进行用户的激活
     * @param model 页面之间互传的数据
     * @param userId 用户的id
     * @param code 页面输送的激活码
     * @return
     */
    @RequestMapping(value = "activation/{userId}/{code}")
    public String loginUser(Model model, @PathVariable("userId") int userId,@PathVariable("code") String code){
        //输出调试日志
        log.info("进行激活用户！");

        //通过 业务 的方法进行判断用户的激活状态
        int result = userService.activation(userId, code);

        //进行判断用户的激活状态
        if (result == CommunityConstant.ACTIVATION_SUCCESS){
            //激活成功
            model.addAttribute("msg","账号激活成功，你可以正常使用我们的任何服务了！");
            model.addAttribute("target","/login");  // 激活成功的页面，点击此连接就会跳转 /login 的 controller 层
        }else if (result == CommunityConstant.ACTIVATION_REPEAT){
            //重复激活
            model.addAttribute("msg","无效操作，账号已经激活！");
            model.addAttribute("target","/index"); //回去登录过的首页
        }else {
            //激活失败
            model.addAttribute("msg","激活失败，您提供的激活码不正确！");
            model.addAttribute("target","/index");  // 返回激活失败，回去没有登录的首页
        }

        return "/site/operate-result";   // 返回到 提示激活成功 的页面
    }


    /**
     * 生成验证码
     * @param response 返回验证码图片到前端
     * @param session 进行 服务器存储 验证码，方便 controller 进行校验
     */
    @RequestMapping(value = "/kaptcha",method = RequestMethod.GET)
    public void getKaptcha(HttpServletResponse response, HttpSession session){
        // 生成验证码
        String text = kaptchaProducer.createText();  // 验证码得文本框
        BufferedImage image = kaptchaProducer.createImage(text); // 根据这个验证码得文本框，创建图片

        // 将验证码存入 session中
        //session.setAttribute("kaptcha",text);

        //将 验证码 存入  redis 中
        String kaptchaOwner = GenerateUtil.generateUUID();
        Cookie cookie = new Cookie("kaptchaOwner", kaptchaOwner);
        //生效时间 60s
        cookie.setMaxAge(60);
        //设置生效的路径，全局生效
        cookie.setPath(contextPath);
        //将 Owner 通过 cookie传回前端，下一次访问的时候携带cookie，我们需要通过 cookie 进行获取 redis 验证码的 key 的字符串
        response.addCookie(cookie);
        //将验证码存入 redis
        String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
        // redis 生效的时间是 60秒
        redisTemplate.opsForValue().set(redisKey,text,60, TimeUnit.SECONDS);

        // 将图片输出到浏览器中
        // 这里的格式千万不要写错了，不然会出现下载的情况，而不是输出到页面，因为浏览器不能识别错误的格式类型，就只好进行下载
        response.setContentType("/image/png");  // 注释当前返回给浏览器得数据是什么类型得
        try {
            // 获取返回得输出流
            OutputStream os = response.getOutputStream();
            // 将图片通过 返回得输出流 输出到浏览器上面
            ImageIO.write(image,"png",os);
        } catch (IOException e) {
            log.info(e.getMessage());
            throw new RuntimeException(e);
        }
    }


    /**
     * 用户注册成功之后的登录 controller
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @param rememberMe 是否点击页面 密码  的 记住我
     * @param model model对象（thymeleaf使用方便），前后端数据的互传，只能自动注入对象，string等普通类型不能注入
     * @param session session会话
     * @param response 返回数据，cookies（携带 ticket）
     * @param kaptchaOwner 获取 名叫 这个 的 cookie 的值
     * @return
     */
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public String login(String username,String password, String code, boolean rememberMe,
                        Model model, HttpSession session,HttpServletResponse response,
                        @CookieValue("kaptchaOwner") String kaptchaOwner){
        //检查验证码,新知识点  equalsIgnoreCase 忽略大小写比较
        //String kaptcha = (String)session.getAttribute("kaptcha");

        String kaptcha = null;
        //查看 cookie 的值是否失效
        if (StringUtils.isNotBlank(kaptchaOwner)){
            String redisKey = RedisKeyUtil.getKaptchaKey(kaptchaOwner);
            kaptcha = (String) redisTemplate.opsForValue().get(redisKey);
        }

        if (StringUtils.isBlank(kaptcha) || StringUtils.isBlank(code) || !kaptcha.equalsIgnoreCase(code)){
            model.addAttribute("codeMsg","验证码不正确！");
            // 返回登录的页面
            return "/site/login";
        }

        //设置 ticket 保留的时间长短，根据是否点击了 密码的记住我
        int expiredSeconds = rememberMe ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;

        // 检查登录的账号，密码
        Map<String,Object> map = userService.login(username,password,expiredSeconds);
        if (map.containsKey("ticket")){
            //登录成功，// TODO: 2022/9/23 这个cookie的工作流程 
            Cookie cookie = new Cookie("ticket", map.get("ticket").toString());
            cookie.setPath(contextPath);
            cookie.setMaxAge(expiredSeconds);  //cookie 的生命周期
            response.addCookie(cookie);  // 返回 cookie

            return "redirect:/index";  // 重定向到 首页
        }else {
            //登录失败
            model.addAttribute("usernameMsg",map.get("usernameMsg"));
            model.addAttribute("passwordMsg",map.get("passwordMsg"));
            return "/site/login";
        }
    }

    /**
     * 登出功能
     * @param ticket 根据 ticket 登出，设置状态码为 1
     * @return
     */
    @RequestMapping(value = "/logout",method = RequestMethod.GET)
    public String logout(@CookieValue("ticket") String ticket){
        userService.logout(ticket);
        //登出用户，需要将 SecurityContext 进行删除
        SecurityContextHolder.clearContext();
        return "redirect:/login"; //跳转登录页面
    }
}

